package common

import (
	"fmt"
	"reflect"

	"gddgame.cc/galaxy/server/web"
)

type AuthHandler func(context web.Context) bool
type Auth struct {
	Id    string
	Field string
}

func (a *Auth) Login(context web.Context, result interface{}) (interface{}, error) {
	fv := reflect.ValueOf(result)
	if fv.Kind() == reflect.Ptr {
		fv = fv.Elem()
	}
	ff := fv.FieldByName(a.Field)
	if isZero(ff) {
		return result, fmt.Errorf("%s field miss", a.Field)
	}
	v := ff.Interface()
	context.Set(a.Id, v)
	return result, nil
}

func (a *Auth) Logout(context web.Context) error {
	context.Set(a.Id, nil)
	return nil
}

func AuthMiddle(authList []AuthHandler, fail func() error) web.Handler {
	return func(context web.Context, next web.Next) error {
		var err error
		if len(authList) == 0 {
			goto Success
		}
		for k, _ := range authList {
			if authList[k](context) {
				goto Success
			}
		}
		err = fail()
		context.SetResponse(err)
		return err
	Success:
		return next(nil)
	}
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Func, reflect.Map, reflect.Slice:
		return v.IsNil()
	case reflect.Array:
		z := true
		for i := 0; i < v.Len(); i++ {
			z = z && isZero(v.Index(i))
		}
		return z
	case reflect.Struct:
		z := true
		for i := 0; i < v.NumField(); i++ {
			z = z && isZero(v.Field(i))
		}
		return z
	}
	// Compare other types directly:
	z := reflect.Zero(v.Type())
	return v.Interface() == z.Interface()
}
